package com.dingreading.cloud.web.controller;

import com.alibaba.fastjson.JSONObject;
import com.dingreading.cloud.common.base.R;
import com.dingreading.cloud.common.util.*;
import com.dingreading.cloud.common.util.wechat.PayExtraUtil;
import com.dingreading.cloud.common.util.wechat.WxPayBusiness;
import com.dingreading.cloud.web.dto.ReadstarGradeBookDto;
import com.dingreading.cloud.web.dto.ReadstarStoreDto;
import com.dingreading.cloud.web.dto.ReadstarStoreDto2;
import com.dingreading.cloud.web.dto.ReadstarStudentDto;
import com.dingreading.cloud.web.entity.*;
import com.dingreading.cloud.web.mapper.ReadstarStudentMapper;
import com.dingreading.cloud.web.service.*;
import com.google.common.collect.Maps;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

@RefreshScope
@RestController
@RequestMapping(value = "/front/readStar")
@Api(tags = "小程序-好读之星2025")
public class ReadStar2025Controller {

    @Value("${mini.store.appId}")
    private String miniAppId;
    @Value("${mini.store.appSecret}")
    private String miniSecret;
    @Value("${readstar.beginDate}")
    private String beginDate;
    @Value("${readstar.endDate}")
    private String endDate;
    @Value("${readstar.payAmount}")
    private Double payAmount;

    // 叮叮文化
    @Value("${wx.mchId}")
    private String mchId;
    @Value("${wx.mchKey}")
    private String mchKey;
    // 支付回调地址
    @Value("${payNotifyUrl}")
    private String notifyUrl;

    @Resource
    protected ReadstarGradeService readstarGradeService;
    @Resource
    protected ReadstarStoreService readstarStoreService;
    @Resource
    protected ReadstarStudentService readstarStudentService;
    @Resource
    protected ReadstarStudentMapper readstarStudentMapper;
    @Resource
    protected ReadstarLogService readstarLogService;
    @Resource
    protected WxMiniUserService miniUserService;
    @Resource
    protected ReadstarUnitService readstarUnitService;
    @Resource
    protected ReadstarPayOrderService readstarPayOrderService;


    @ApiOperation(value = "获取小程序登录用户的unionid和openid")
    @PostMapping(value = "/getUnionidAndOpenid", produces = "application/json; charset=UTF-8")
    public R<Object> getUnionidAndOpenid(
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid", required = false) String storeUid,
            @ApiParam(value = "分享小程序的用户标识") @RequestParam(value = "shareOpenid", required = false) String shareOpenid,
            @ApiParam(value = "渠道标识") @RequestParam(value = "channelUid", required = false) String channelUid,
            @ApiParam(value = "wx.login 接口获得临时登录凭证") @RequestParam(value = "code") String code
    ) throws Exception {
        if (StringUtils.isBlank(code))
            return R.fail("未传递小程序临时登录凭证");

        // 获取小程序登录用户信息
        JSONObject jsonObject = WxMiniUtil.Init().getUnionidAndOpenid(miniAppId, miniSecret, code);

        String openid = jsonObject.getString("openid");
        if (StringUtils.isNotBlank(openid)) {
            String unionid = jsonObject.getString("unionid");
            WxMiniUser miniUser = miniUserService.getByOpenid(openid);
            Date time = DateUtil.getNowDatetime();
            if (miniUser == null) {
                miniUser = new WxMiniUser();
                if (StringUtils.isNotBlank(unionid))
                    miniUser.setUnionid(unionid);
                miniUser.setOpenid(openid);
                miniUser.setShareOpenid(shareOpenid);
                miniUser.setOriginStoreUid(storeUid);
                miniUser.setRemark("门店宝小程序-好读之星");
                miniUser.setSource(EnumType.Source.XCX_MDB.getName());
                miniUser.setAddTime(time);
            }
            if (StringUtils.isNotBlank(storeUid))
                miniUser.setStoreUid(storeUid);
            if (StringUtils.isNotBlank(channelUid)) {
                miniUser.setChannelUid(channelUid);
                miniUser.setChannelName("");
            }
            miniUser.setEditTime(time);
            miniUserService.saveOrUpdate(miniUser);

            ReadstarLog log = new ReadstarLog();
            log.setType(1);
            log.setOpenid(openid);
            readstarLogService.saveOrUpdate(log);

            jsonObject.put("storeUid", miniUser.getStoreUid());
            jsonObject.put("channelUid", miniUser.getChannelUid());
        }

        return R.ok(jsonObject);
    }

    @ApiOperation(value = "获取参加活动的门店列表")
    @PostMapping(value = "/getStoreNameList", produces = "application/json; charset=UTF-8")
    public R<Object> getStoreNameList(
            @ApiParam(value = "经度") @RequestParam(value = "lng", required = false) String lng,
            @ApiParam(value = "纬度") @RequestParam(value = "lat", required = false) String lat
    ) throws Exception {
        List<ReadstarStoreDto2> list = readstarStoreService.storeNameList();
        if (CollectionUtils.isNotEmpty(list)) {
            if (StringUtils.isNotBlank(lat) && StringUtils.isNotBlank(lng)) {
                List<ReadstarStoreDto2> newList = new ArrayList<>();
                List<ReadstarStoreDto2> list1 = new ArrayList<>();
                List<ReadstarStoreDto2> list2 = new ArrayList<>();
                for (ReadstarStoreDto2 dto : list) {
                    if (StringUtils.isNotBlank(dto.getLat()) && StringUtils.isNotBlank(dto.getLng())) {
                        list1.add(dto);
                    } else {
                        list2.add(dto);
                    }
                }
                if (CollectionUtils.isNotEmpty(list1)) {
                    // 方法1：使用简化距离排序
                    List<ReadstarStoreDto2> sortedList = list1.stream()
                            .sorted(Comparator.comparingDouble(dto -> distanceTo(lat, lng, dto.getLat(), dto.getLng())))
                            .collect(Collectors.toList());
                    int index = Math.min(sortedList.size(), 5);
                    for (int j = 0; j < index; j++) {
                        ReadstarStoreDto2 dto = sortedList.get(j);
                        String phone = dto.getPhone();
                        if (StringUtils.isNotBlank(phone)) {
                            String storeName = dto.getStoreName();
                            dto.setStoreName(storeName + "询:" + phone);
                        }
                    }
                    newList.addAll(sortedList);
                }
                if (CollectionUtils.isNotEmpty(list2)) {
                    if (CollectionUtils.isEmpty(list1)) {
                        int index = Math.min(list2.size(), 5);
                        for (int j = 0; j < index; j++) {
                            ReadstarStoreDto2 dto = list2.get(j);
                            String phone = dto.getPhone();
                            if (StringUtils.isNotBlank(phone)) {
                                String storeName = dto.getStoreName();
                                dto.setStoreName(storeName + "询:" + phone);
                            }
                        }
                    }
                    newList.addAll(list2);
                }
                return R.ok(newList);
            } else {
                int index = Math.min(list.size(), 5);
                for (int j = 0; j < index; j++) {
                    ReadstarStoreDto2 dto = list.get(j);
                    String phone = dto.getPhone();
                    if (StringUtils.isNotBlank(phone)) {
                        String storeName = dto.getStoreName();
                        dto.setStoreName(storeName + "询:" + phone);
                    }
                }
            }
        }

        return R.ok(list);
    }

    @ApiOperation(value = "根据省市区选择门店")
    @PostMapping(value = "/getStoreList", produces = "application/json; charset=UTF-8")
    public R<Object> getStoreList(
            @ApiParam(value = "省") @RequestParam(value = "province") String province,
            @ApiParam(value = "市") @RequestParam(value = "city", required = false) String city,
            @ApiParam(value = "区") @RequestParam(value = "county", required = false) String county
    ) throws Exception {
        List<ReadstarStoreDto> list = readstarStoreService.listByProvince(province, city, county);
        for (ReadstarStoreDto dto : list) {
            String phone = dto.getPhone();
            if (StringUtils.isNotBlank(phone)) {
                String address = dto.getAddress();
                dto.setAddress(address + " 询:" + phone);
            }
        }
        return R.ok(list);
    }

    @ApiOperation(value = "获取指导单位和主办单位")
    @PostMapping(value = "/getUnitList", produces = "application/json; charset=UTF-8")
    public R<Object> getUnitList() throws Exception {
        List<ReadstarUnit> list = readstarUnitService.listAll();
        if (CollectionUtils.isNotEmpty(list)) {
            LinkedHashMap<Integer, List<ReadstarUnit>> map = list.stream()
                    .collect(Collectors.groupingBy(ReadstarUnit::getType, LinkedHashMap::new, Collectors.toList()));

            JSONObject jsonObject = new JSONObject();
            jsonObject.put("guidance", map.get(1));
            jsonObject.put("organizers", map.get(2));
            jsonObject.put("sponsors", map.get(3));
            return R.ok(jsonObject);
        }
        return R.ok();
    }

    @ApiOperation(value = "获取年级和书籍")
    @PostMapping(value = "/getGradeAndBook", produces = "application/json; charset=UTF-8")
    public R<Object> getGradeAndBook() throws Exception {
        List<ReadstarGradeBookDto> list = readstarGradeService.gradeAndBookList();

        return R.ok(list);
    }

    @ApiOperation(value = "获取已报名学生")
    @PostMapping(value = "/listByOpenid", produces = "application/json; charset=UTF-8")
    public R<Object> listByOpenid(
            @ApiParam(value = "微信用户id") @RequestParam(value = "openid") String openid
    ) throws Exception {
        List<ReadstarStudentDto> list = readstarStudentService.listByOpenid(openid);

        return R.ok(list);
    }

    @ApiOperation(value = "获取已报名学生")
    @PostMapping(value = "/get", produces = "application/json; charset=UTF-8")
    public R<Object> get(
            @ApiParam(value = "微信用户id") @RequestParam(value = "openid") String openid,
            @ApiParam(value = "学生uid") @RequestParam(value = "studentUid") String studentUid
    ) throws Exception {
        ReadstarStudentDto dto = readstarStudentService.getByOpenidAndStudentUid(openid, studentUid);
        if (dto == null) {
            return R.fail("未获取到报名信息");
        }

        return R.ok(dto);
    }

    @ApiOperation(value = "判断当前日期能否能报名")
    @PostMapping(value = "/judgeRegister", produces = "application/json; charset=UTF-8")
    public R<Object> judgeRegister(
            @ApiParam(value = "微信用户id") @RequestParam(value = "openid") String openid
    ) throws Exception {
        String msg = judgeSignUp(beginDate, endDate);
        if (StringUtils.isNotBlank(msg)) {
            return R.fail(msg);
        }

        return R.ok();
    }

    @ApiOperation(value = "学生报名")
    @PostMapping(value = "/register", produces = "application/json; charset=UTF-8")
    public R<Object> register(
            @ApiParam(value = "学生uid") @RequestParam(value = "uid", required = false) String uid,
            @ApiParam(value = "门店uid") @RequestParam(value = "storeUid") String storeUid,
            @ApiParam(value = "门店名称") @RequestParam(value = "storeName") String storeName,
            @ApiParam(value = "省") @RequestParam(value = "province") String province,
            @ApiParam(value = "市") @RequestParam(value = "city") String city,
            @ApiParam(value = "区") @RequestParam(value = "county", required = false) String county,
            @ApiParam(value = "微信用户id") @RequestParam(value = "openid") String openid,
            @ApiParam(value = "手机号") @RequestParam(value = "phone") String phone,
            @ApiParam(value = "姓名") @RequestParam(value = "userName") String userName,
            @ApiParam(value = "年级") @RequestParam(value = "grade") Integer grade,
            @ApiParam(value = "书名") @RequestParam(value = "bookName") String bookName
    ) throws Exception {
        if (StringUtils.isBlank(storeUid))
            return R.fail("门店标识未传递");
        if (StringUtils.isBlank(openid))
            return R.fail("微信用户uid未传递");
        if (StringUtils.isBlank(userName))
            return R.fail("请填写姓名");
        if (StringUtils.isBlank(phone) || phone.length() != 11)
            return R.fail("手机号码格式错误");
        if (grade == null)
            return R.fail("请选择年级");
        if (StringUtils.isBlank(bookName))
            return R.fail("请选择书籍");
        if (StringUtils.isBlank(province))
            return R.fail("请选择省");
        if (StringUtils.isBlank(city))
            return R.fail("请选择市");

        String msg = judgeSignUp(beginDate, endDate);
        if (StringUtils.isNotBlank(msg)) {
            return R.fail(msg);
        }

        boolean b = readstarStudentService.exitPhoneAndUserName(uid, phone, userName);
        if (b)
            return R.fail("姓名和手机号已报名");

        ReadstarStudent data = null;
        if (StringUtils.isBlank(uid)) {
            long count = readstarStudentService.getCount(openid);
            if (count >= 5)
                return R.fail("已报名5次，请更换微信号报名");

            data = new ReadstarStudent();
            data.setUid(KitUtil.getUuid());
            data.setOpenid(openid);
        } else {
            data = readstarStudentService.getByUid(uid);
            if (data == null) {
                return R.fail("报名信息获取失败");
            }
        }
        data.setStoreUid(storeUid);
        data.setStoreName(storeName);
        data.setProvince(province);
        data.setCity(city);
        data.setCounty(county);
        data.setPhone(phone);
        data.setUserName(userName);
        data.setGrade(grade);
        data.setBookName(bookName);

        String orderUid = "";
        // 创建订单
        ReadstarPayOrder payOrder = newOrder(province, city, data.getUid(), data.getOrderUid());
        if (payOrder != null) {
            orderUid = payOrder.getOrderUid();
            data.setOrderUid(orderUid);
            readstarPayOrderService.saveOrUpdate(payOrder);
        }
        readstarStudentMapper.insertOrUpdate(data, true);

        return R.ok(orderUid);
    }

    @ApiOperation(value = "发起微信小程序支付")
    @PostMapping(value = "/wxMiniPay", produces = "application/json; charset=UTF-8")
    public R<Object> wxMiniPay(
            HttpServletRequest request,
            @RequestParam(value = "orderUid") @ApiParam(value = "订单uid") String orderUid,
            @RequestParam(value = "openid") @ApiParam(value = "微信openid") String openid
    ) {
        // 查询充值订单流水号
        ReadstarPayOrder order = readstarPayOrderService.getByOrderUid(orderUid);
        // 判断订单状态
        if (order == null) return R.fail("订单获取失败");
        if (order.getPayStatus().equals(1)) return R.fail("订单已被支付");
        if (order.getPayAmount() <= 0) return R.fail("订单的付款金额错误");
        if (DateUtil.getNowDatetime().getTime() > order.getExpireTime().getTime())
            return R.fail("订单有效已过期");

        // 微信付款二维码
        Map<String, String> map = Maps.newHashMap();
        map.put("openid", openid);
        map.put("OutTradeNo", order.getOrderCode());
        map.put("body", "好读之星物料");
        map.put("fee", String.valueOf(order.getPayAmount()));
        map.put("tradeType", EnumType.TradeType.WECHAT_JSAPI.getType());
        map.put("attach", PayExtraUtil.getJsonString(EnumType.CodeType.RD.getType()));
        // 获取统一下单后的参数
        try {
            Map<String, String> payMap = WxPayBusiness.Init().miniUnifiedOrderBusiness(request, map, miniAppId, mchId, mchKey, notifyUrl);
            return R.ok(payMap);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return R.fail("收银台-微信付款公众号，发起支付异常");
    }

    /**
     * 验证能否报名
     */
    private String judgeSignUp(String beginDate, String endDate) throws Exception {
        if (StringUtils.isBlank(beginDate) || StringUtils.isBlank(endDate))
            return "报名日期获取失败";
        // 判读活动开始时间和结束时间
        Date bgnDate = DateUtil.parseDate(beginDate);
        Date enDate = DateUtil.parseDate(endDate);
        String today = DateUtil.getNowDateStr();
        Date todayDate = DateUtil.parseDate(today);
        if (todayDate.getTime() < bgnDate.getTime())
            return "报名日期:" + beginDate + "至" + endDate;
        if (todayDate.getTime() > enDate.getTime())
            return "报名已结束";
        return "";
    }


    // 计算两点之间的距离（简化版，不考虑地球曲率）
    public double distanceTo(String refLat, String refLon, String latitude, String longitude) {
        return Math.sqrt(Math.pow(Double.parseDouble(latitude) - Double.parseDouble(refLat), 2) + Math.pow(Double.parseDouble(longitude) - Double.parseDouble(refLon), 2));
    }


    /**
     * 创建订单
     */
    private ReadstarPayOrder newOrder(String province, String city, String studentUid, String orderUid) throws Exception {
        ReadstarPayOrder payOrder = null;
        if (province.equals("安徽省") && city.equals("合肥市")) {
            if (StringUtils.isNotBlank(orderUid)) {
                payOrder = readstarPayOrderService.getByOrderUid(orderUid);
                if (payOrder == null) {
                    throw new DescribeException("订单获取失败");
                }
                Date nowtime = DateUtil.getNowDatetime();
                if (payOrder.getPayStatus().equals(0) && payOrder.getExpireTime().getTime() < nowtime.getTime()) {

                    payOrder = new ReadstarPayOrder();
                    payOrder.setStudentUid(studentUid);
                    payOrder.setPayAmount(payAmount);
                    payOrder.setOrderUid(KitUtil.getUuid());
                    payOrder.setOrderCode(KitUtil.getReadstarOrderCode());
                    payOrder.setPayType(1);
                    payOrder.setPayCorp(1);
                    payOrder.setBuyNum(1);
                    payOrder.setPayStatus(0);
                    // 一小时后过期
                    Date expireTime = DateUtil.addHours(DateUtil.getNowDatetime(), 1);
                    payOrder.setExpireTime(expireTime);
                }
            } else {
                // 创建订单
                payOrder = new ReadstarPayOrder();
                payOrder.setStudentUid(studentUid);
                payOrder.setPayAmount(payAmount);
                payOrder.setOrderUid(KitUtil.getUuid());
                payOrder.setOrderCode(KitUtil.getReadstarOrderCode());
                payOrder.setPayType(1);
                payOrder.setPayCorp(1);
                payOrder.setBuyNum(1);
                payOrder.setPayStatus(0);
                // 一小时后过期
                Date expireTime = DateUtil.addHours(DateUtil.getNowDatetime(), 1);
                payOrder.setExpireTime(expireTime);
            }
        }

        return payOrder;
    }

}
